#ifndef functorsH
#define functorsH

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

#include <stdexcept>
#include <vector>
#include <string>

#include "big_int.h"
#include "functions.h"

namespace implementation
{
	using std::exception;
	using std::string;
	using std::vector;
	
	using boost::phoenix::function;
	
	string vector_to_string(vector<char>);
	
	struct big_int_implementation
	{
		template<typename T>
		struct result
		{
			typedef big_int type;
		};
		
		template<typename T>
		big_int operator()(T a) const
		{
			return big_int(vector_to_string(a));
		}
	};
	function<implementation::big_int_implementation>& big_int_constructor();	
	
	big_int power(big_int, big_int);
	
	struct power_implementation
	{
		template<typename T_1, typename T_2>
		struct result
		{
			typedef big_int type;
		};
		
		template<typename T_1, typename T_2>
		big_int operator()(T_1 a, T_2 b) const
		{
			if (b < 0)
				throw exception("negative power");
			return power(a, b);
		}
	};
	function<implementation::power_implementation>& power();
	
	struct function_implementation
	{
		template<typename T_1, typename T_2>
		struct result
		{
			typedef big_int type;
		};
		
		template<typename T_1, typename T_2>
		big_int operator()(T_1 name, T_2 arg) const
		{
			return get_functions()[name](arg);
		}
	};
	function<implementation::function_implementation>& function_();
}

#endif
